package com.easymin.weixin.controller.v5;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.easymin.weixin.controller.v4.ResultTransport;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.easymin.weixin.common.WxUtils;
import com.easymin.weixin.common.api.DaijiaApi;
import com.easymin.weixin.common.api.PassengerApi;
import com.easymin.weixin.common.api.ZhuanApi;
import com.easymin.weixin.controller.v5.utils.ErrorMapV5;
import com.easymin.weixin.controller.v5.utils.JsonUtil;
import com.easymin.weixin.controller.v5.utils.ResultV5;
import com.easymin.weixin.entity.WxAccount;
import com.easymin.weixin.entity.WxApplication;
import com.easymin.weixin.entity.passenger.Passenger;
import com.easymin.weixin.manager.WxAccountManager;
import com.easymin.weixin.manager.WxApplicationManager;
import com.google.common.base.Preconditions;

/**
 * 专车信息控制器
 * @author zane
 *
 */
@Controller
@RequestMapping("v5/zhuanche/")
public class ZhuanCheController {
	
	private static final String WX_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";

	private static final String WX_JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={access_token}&type=jsapi";

	@Autowired
	private WxApplicationManager wxApplicationManager;

	@Autowired
	private WxAccountManager wxAccountManager;
	
	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private ZhuanApi zhuanApi;

	@Autowired
	private DaijiaApi daijiaApi;
	
	@Autowired
	private PassengerApi passengerApi;
	


	/**
	 * 获取附近的车辆数
	 * @param appKey 系统key
	 * @param lat 
	 * @param lng 
	 * @param carTypes 已选的车辆类型，逗号分隔
	 * @return
	 */
	@ResponseBody
	@RequestMapping("coutNearDrivers")
	@SuppressWarnings("unchecked")
	public ResultV5 coutNearDrivers(String appKey, Double lat, Double lng, String carTypes) {
		try {
			WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
			Preconditions.checkArgument(null != wxApplication, "appKey错误"); 
			
			Map<String, Object> carTypesMap = new HashMap<String, Object>();

			String carTypeRecode = null; // 记录下类型，相同就不去调用了
			JSONObject jsonObject = null;
			int countSun = 0;

			// 获取每种类型的车的数量，距离
			String [] carTypes_ = carTypes.split(",");
			for (String carType : carTypes_) {

				if (StringUtils.isBlank(carType)){
					continue;
				}

				Map<String, Object> carTypeCountInfo = null;

				// 与上次记录报的类型不一样再去调用
				if (null == carTypeRecode || !carType.equals(carTypeRecode)) {
					jsonObject = daijiaApi.countZhuancheNearDriver(wxApplication.getAddress(), lng, lat, Long.parseLong(carType));
				}

				// 计算数量
				if (jsonObject.getBooleanValue("success")) {
					JSONArray jsonArray = jsonObject.getJSONArray("data");
					int count = 0;
					int size = jsonArray.size();
					// 有该类型的数量记录就取出来
					if (null != carTypesMap && carTypesMap.containsKey(carType)) {
						carTypeCountInfo = (Map<String, Object>) carTypesMap.get(carType);
						count = Integer.parseInt(String.valueOf(carTypeCountInfo.get("count")));
					}
					countSun += size;
					count += size;
					if (null == carTypeCountInfo) {
						carTypeCountInfo = new HashMap<String, Object>();
					}
					carTypeCountInfo.put("count", count);
					carTypesMap.put(carType, carTypeCountInfo);
					carTypeRecode = carType;
				}
			}

			// 返回
			ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
			carTypesMap.put("countSun", countSun);
			result.setData(carTypesMap);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return ErrorMapV5.ERR_SYSTEM;
		}
	}

	/**
	 * 预算专车费用.
	 * @param appKey 系统key
	 * @param areaIdAndTypeIds 收费ID，逗号分隔
	 * @param startLat 开始纬度
	 * @param startLng 开始经度
	 * @param endLat 结束纬度
	 * @param endLng 结束经度
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@ResponseBody
	@RequestMapping("calculationPrice")
	public ResultV5 calculationPrice(
			@RequestParam(value="appKey") String appKey,
			@RequestParam(value="areaIdAndTypeIds") String areaIdAndTypeIds,
			@RequestParam(value="startLat") Double startLat, 
			@RequestParam(value="startLng") Double startLng, 
			@RequestParam(value="endLat", required=false) Double endLat, 
			@RequestParam(value="endLng", required=false) Double endLng) throws Exception {

		try {
			WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
			Preconditions.checkArgument(null != wxApplication, "appKey错误");

			Map<String, Object> priceMap = null;
			Map<String, Object> priceObj = new HashMap<String, Object>();

			Long areaIdRecode = null;
			// 所有车型的总计费用
			double countMoney = 0.0;
			// 所有车型的总的公里数
			double countMileage = 0.0;
			
			List<Map<String, ?>> areaIdAndTypeIds_ = JsonUtil.Parse2List(areaIdAndTypeIds);
			if (CollectionUtils.isNotEmpty(areaIdAndTypeIds_)) {
				for (Map<String, ?> areaIdAndTypeId : areaIdAndTypeIds_) {

					Long areaId = Long.parseLong(String.valueOf(areaIdAndTypeId.get("areaId")));
					Long typeId = Long.parseLong(String.valueOf(areaIdAndTypeId.get("typeId")));
					// 记录每种类型的车辆的数量
					Integer typeNumber = 0;

					// 调起接口，该车型调用记录已经不存在时，再去调用
					if (null == areaIdRecode || !areaIdRecode.equals(areaId)) {
						JSONObject jsonObject = daijiaApi.calculationZhuanchePriceV4(wxApplication.getAddress(), areaId, startLat, startLng, endLat, endLng);
						if(null != jsonObject && jsonObject.size() > 0) {
							if (jsonObject.getBoolean("success")) {
								// 定义累加数据字段
								// 费用
								double money = 0.0;
								// 执行时间 分钟
								long travelTime = 0L;
								// 起步价
								double startPrice = 0.0;
								// 行驶里程 公里
								double mileage = 0.0;
								// 行驶里程费用
								double mileagePrice = 0.0;
								// 服务时间费用
								double travelTimePrice = 0.0;

								// 不同的类型赋初始值
								if (null != priceObj && priceObj.containsKey(String.valueOf(typeId))) {
									priceMap = (Map<String, Object>) priceObj.get(String.valueOf(typeId));
									money = priceMap.get("money") == null ? 0.0 : Double.parseDouble(String.valueOf(priceMap.get("money")));
									startPrice = priceMap.get("startPrice") == null ? 0.0 : Double.parseDouble(String.valueOf(priceMap.get("startPrice")));
									travelTime = priceMap.get("travelTime") == null ? 0L : Long.parseLong(String.valueOf(priceMap.get("travelTime")));
									mileage = priceMap.get("mileage") == null ? 0.0 : Double.parseDouble(String.valueOf(priceMap.get("mileage")));
									mileagePrice = priceMap.get("mileagePrice") == null ? 0.0 : Double.parseDouble(String.valueOf(priceMap.get("mileagePrice")));
									travelTimePrice = priceMap.get("travelTimePrice") == null ? 0.0 : Double.parseDouble(String.valueOf(priceMap.get("travelTimePrice")));
									typeNumber = priceMap.get("typeNumber") == null ? 0 : Integer.parseInt(String.valueOf(priceMap.get("typeNumber")));
								} else {
									priceMap = new HashMap<String, Object>();
								}

								JSONObject data = jsonObject.getJSONObject("data");
								countMoney += data.getDoubleValue("money");
								countMileage += data.getDoubleValue("mileage");

								// 累加数据
								money += data.getDoubleValue("money");
								travelTime += data.getDoubleValue("travelTime");
								startPrice += data.getDoubleValue("startPrice");
								mileage += data.getDoubleValue("mileage");
								mileagePrice += data.getDoubleValue("mileagePrice");
								travelTimePrice += data.getDoubleValue("travelTimePrice");
								typeNumber++;

								// 更新数据
								priceMap.put("travelTime", travelTime);
								priceMap.put("money", money);
								priceMap.put("startPrice", startPrice);
								priceMap.put("mileage", mileage);
								priceMap.put("mileagePrice", mileagePrice);
								priceMap.put("travelTimePrice", travelTimePrice);
								priceMap.put("typeNumber", typeNumber);
								priceMap.put("areaId", areaId);

								priceObj.put(String.valueOf(typeId), priceMap);

								// 记录本次的类型，如果下次与本次相同，就不去调用接口了，节约资源
								areaIdRecode = areaId;
							}
						}
					}

				}
			}

			priceObj.put("countMoney", countMoney);
			priceObj.put("countMileage", countMileage);

			// 返回数据
			ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
			result.setData(priceObj);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return ErrorMapV5.ERR_SYSTEM;
		}
	}

	/**
	 * 专车预约订单（下单）
	 * @param passengerId 用户id
	 * @param passengerPhone 用户电话
	 * @param passengerName 用户名称
	 * @param userPhone 若为其他人下单，则，这里是其他人的电话
	 * @param companyId 公司id
	 * @param companyName 公司名称
	 * @param serverTime 服务时间
	 * @param startAddress 开始地址信息
	 * @param startAddressDetail 开始地址详细信息   非必须
	 * @param startLat 开始lat
	 * @param startLng 开始lng
	 * @param carTypes 车辆类型集合
	 * @param appKey 系统Key
	 * @param endAddress 结束地址  非必须
	 * @param endAddressDetail 结束地址详细信息  非必须
	 * @param endLat 结束lat  非必须
	 * @param endLng 结束lng  非必须
	 * @param travelTime 服务时长（预算接口返回）   非必须
	 * @param mileage 公里数   非必须
	 * @param prePay 是否预支付  非必须
	 * @param memo 用车需求  非必须
	 * @param flightNo 航班号  非必须
	 * @param trainNo 车次号  非必须
	 * @param operator 操作人  非必须
	 * @param serviceTypeId 服务类型id  非必须
	 * @param serviceType 服务类型  非必须
	 * @param couponIds 优惠券ID  非必须
	 * @param couponMoney 优惠券各车型优惠的总金额  非必须
	 * @param createOrderName 创建的订单名称  非必须
	 * @return
	 * @throws Exception 
	 */
	@ResponseBody
	@RequestMapping(value="createOrder", method={RequestMethod.POST})
	public ResultV5 createOrder (
			@RequestParam(required = true, value="passengerId") Long passengerId,
	        @RequestParam(required = true, value="passengerPhone") String passengerPhone,
	        @RequestParam(required = true, value="passengerName") String passengerName,
	        @RequestParam(required = true, value="userPhone") String userPhone,
	        @RequestParam(required = true, value="companyId") Long companyId,
	        @RequestParam(required = true, value="companyName") String companyName,
	        @RequestParam(required = true, value="channelName") String channelName,
	        @RequestParam(required = true, value="serverTime") Long serverTime,
	        @RequestParam(required = true, value="startAddress") String startAddress,
	        @RequestParam(required = true, value="startLat") Double startLat,
	        @RequestParam(required = true, value="startLng") Double startLng,
	        @RequestParam(required = true, value="appKey") String appKey,
	        @RequestParam(required = true, value="carTypes") String carTypes,
	        @RequestParam(required = false, value = "startAddressDetail") String startAddressDetail,
	        @RequestParam(required = false, value = "endAddress") String endAddress,
	        @RequestParam(required = false, value = "endAddressDetail") String endAddressDetail,
	        @RequestParam(required = false, value = "endLat") Double endLat,
	        @RequestParam(required = false, value = "endLng") Double endLng,
	        @RequestParam(required = false, value = "travelTime") Integer travelTime,
	        @RequestParam(required = false, value = "mileage") Double mileage,
	        @RequestParam(required = false, value = "prePay") Boolean prePay,
	        @RequestParam(required = false, value = "memo") String memo,// 用车需求
	        @RequestParam(required = false, value = "flightNo") String flightNo,// 航班号
	        @RequestParam(required = false, value = "trainNo") String trainNo,// 车次号
	        @RequestParam(required = false, value = "operator") String operator,// 操作人
	        @RequestParam(required = false, value = "serviceTypeId") Long serviceTypeId,
	        @RequestParam(required = false, value = "serviceType") String serviceType,
	        @RequestParam(required = false, value = "couponIds") String couponIds,// 后台传的参数
	        @RequestParam(required = false, value = "couponMoney") Double couponMoney,// 优惠券各车型优惠的总金额
	        @RequestParam(required = false, value = "driverId") Long driverId,// 指定司机下单
	        @RequestParam(required = false, value = "createOrderName") String createOrderName
	        ) throws Exception {
		
		try {
			ResultV5 result = null;
			
			WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
			String serverUrl = wxApplication.getAddress(); // 代驾项目服务器地址
			
			Passenger passenger = passengerApi.findById(passengerId, appKey);
			if(passenger.getInBlackList()){
				result = ErrorMapV5.ERR_SYSTEM;
				return result;
			}
			
			// 调起接口
			String rs = zhuanApi.createOrderV5(passengerId, passengerPhone, passengerName, userPhone, companyId, 
					companyName, channelName, serverTime, startAddress, startLat, startLng, appKey, carTypes, startAddressDetail, 
					endAddress, endAddressDetail, endLat, endLng, travelTime, mileage, prePay, memo, flightNo, trainNo, operator, 
					serviceTypeId, serviceType, serverUrl, couponIds, couponMoney, createOrderName,driverId);

			// 返回结果
			JSONObject data = JSONObject.parseObject(rs);
			if (null != data && data.getIntValue("code") == 0) {
				result = ErrorMapV5.ERR_SUCCESS.clone();
				result.setData(JsonUtil.Parse(rs, JSONObject.class).getJSONObject("data"));
			} else {
				result = new ResultV5(data.getIntValue("code"), data.getString("message"));
				result.setData(JsonUtil.Parse(rs, JSONObject.class).getJSONObject("data"));
			}
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return ErrorMapV5.ERR_SYSTEM;
		}
	}

	/**
	 * 获取未支付订单数量
	 * @param appKey 系统KEY
	 * @param passengerId 客户ID
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value="getCountNotPayOrders", method={RequestMethod.GET})
	public ResultV5 getCountNotPayOrders (
			@RequestParam(required=true, value="appKey") String appKey,
			@RequestParam(required=true, value="passengerId") Long passengerId) {
		
		Long count = zhuanApi.countNotPayAmounts(passengerId, appKey);
		ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
		result.setData(count);
		return result;
	}

	/**
	 * 获取单个订单的评价
	 * @param appKey 系统Key
	 * @param orderId 订单ID
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value="getReview", method={RequestMethod.GET})
	public ResultV5 getReviewByOrderId (
			@RequestParam(required=true, value="appKey") String appKey, 
			@RequestParam(required=true, value="orderId") Long orderId) {
		JSONObject json = zhuanApi.getReviewByOrderId(appKey, orderId);
		ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
		result.setData(json.getJSONObject("data"));
		return result;
	}

	/**
	 * 微信支付.
	 * @param appKey 系统key
	 * @param orderId 订单id
	 * @param openId 微信id
	 * @param appId 微信应用id
	 * @param request 判断是否来自微信
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "doPayForWx", method = RequestMethod.POST)
	public ResultV5 doPayForWx(@RequestParam(required = true, value = "appKey") String appKey,
			@RequestParam(required = true, value = "orderId") Long orderId,
			@RequestParam(required = true, value = "openId") String openId,
			@RequestParam(required = true, value = "appId") String appId, HttpServletRequest request) {

		ResultV5 result = null;
		try {
			WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
			Preconditions.checkArgument(null != wxApplication, "appKey错误");

			WxAccount wxAccount = wxAccountManager.findBy(appId, wxApplication.getId());
			Preconditions.checkArgument(null != wxAccount, "appid错误");

			// 判断是否来自微信
			StringBuilder sb = new StringBuilder();
			sb.append(request.getScheme());
			sb.append("://");
			sb.append(request.getServerName());
			int port = request.getServerPort();
			if (port != 80) {
				sb.append(":").append(port);
			}
			sb.append(request.getRequestURI());
			String queryString = request.getQueryString();
			if (StringUtils.isNotBlank(queryString)) {
				sb.append("?");
				sb.append(queryString);
			}

			JSONObject jsonObject = new JSONObject();
			JSONObject jo = daijiaApi.getZcWxPrepayId(wxApplication.getAddress(), orderId, openId);
			jsonObject.put("package", jo.getString("package"));
			jsonObject.put("timestamp", jo.getString("timeStamp"));
			jsonObject.put("url", sb.toString());
			jsonObject.put("nonceStr", jo.getString("nonceStr"));
			jsonObject.put("paySign", jo.getString("paySign"));

			// 获取微信AccessToken
			String response = restTemplate.getForObject(WX_ACCESS_TOKEN, String.class, wxAccount.getWxappId(),
					wxAccount.getAppsecret());
			JSONObject ac = JSON.parseObject(response);

			if (ac.containsKey("access_token")) {
				String accessToken = ac.getString("access_token"); // 获取微信access_token
				// 获取jsapi_ticket
				String resp = restTemplate.getForObject(WX_JSAPI_TICKET, String.class, accessToken);
				JSONObject ticketJson = JSON.parseObject(resp);
				if (ticketJson.containsKey("ticket")) {
					String ticket = ticketJson.getString("ticket");
					jsonObject.put("jsapi_ticket", ticket);
					Map<String, Object> signParams = new HashMap<>();
					signParams.put("jsapi_ticket", ticket);
					signParams.put("timestamp", jo.getString("timeStamp"));
					signParams.put("url", sb.toString());
					signParams.put("noncestr", jo.getString("nonceStr"));
					jsonObject.put("signature", WxUtils.buildSha1Sign(signParams));

					result = ErrorMapV5.ERR_SUCCESS.clone();
					result.setData(jsonObject);
					return result;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return ErrorMapV5.ERR_SYSTEM;
		}
		return ErrorMapV5.ERR_GET_WECHAT_PAY_PARAMS;
	}


    @ResponseBody
    @RequestMapping("getZhuanDriver")
    public ResultV5 coutNearDrivers(String appKey,Long driverId) {
        try {
            WxApplication wxApplication = wxApplicationManager.findByAppKey(appKey);
            Preconditions.checkArgument(null != wxApplication, "appKey错误");
            JSONObject jsonObject = daijiaApi.getZhuanDriver(wxApplication.getAddress(),driverId);
            // 返回
            ResultV5 result = ErrorMapV5.ERR_SUCCESS.clone();
            result.setData(JSONObject.parse(jsonObject.getString("data")));
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return ErrorMapV5.ERR_SYSTEM;
        }
    }
}
